Skip to content

Apply regression target transforms to the unnormalized target [RES-2639] - #1199

Open
bejaeger wants to merge 1 commit into
benjamin/res-2639-target-encoder-refactorfrom
benjamin/res-2639-transform-unnormalized-target
Open

Apply regression target transforms to the unnormalized target [RES-2639]#1199
bejaeger wants to merge 1 commit into
benjamin/res-2639-target-encoder-refactorfrom
benjamin/res-2639-transform-unnormalized-target

Conversation

@bejaeger

Copy link
Copy Markdown
Collaborator

Closes RES-2639. Stacked on #1198 (targets that branch, so this diff is only the behaviour change); review #1198 first.

Change

One swap, in make_target_transform: the preset reshapes the target in its original units, and the result is standardized afterwards.

-            (STANDARDIZE_STEP, StandardizeTarget()),
             (TARGET_TRANSFORM_STEP, transform),
+            (STANDARDIZE_STEP, StandardizeTarget()),

Applied to a z-normalised target, 1_plus_log was log1p of a z-score — undefined below -1, so for a symmetric target ~15% of rows came out non-finite and reached the model, the log presets carrying no scaler of their own. safepower was fitted on standardized values, where yeo-johnson cannot reach the log limit that removes skew from a heavy right tail.

Also resolves the "none" preset to no transform (it is the identity, so composing it only costs a pass over the target), and fixes the _transform_labels_one docstring, which called its input "unprocessed" — the ticket's second item.

Impact

Changes the v2 / v2.5 / v3 defaults, whose ensembles use safepower for half of their estimators. Unaffected: the v2.6 default ("none"), n_estimators=1 on any version, and every estimator whose target transform is None.

Validation

TabArena regression, 13 datasets, 222 splits per arm, 8 estimators, checkpoint x49jl1p6, 1332 fits, no failures (full report on the ticket):

comparison rmse mae 1−r2 better (rmse)
this change vs base −0.031% −0.069% −0.062% 9/13
no power transform vs base +0.069% −0.080% +0.140% 5/13

Errors, so negative is better. Gains concentrate on heavy-tailed positive targets: healthcare_insurance_expenses −0.23%, diamonds −0.16%, physiochemical_protein −0.13%.

That run measured these semantics through an earlier implementation (80bf5fa0, which composed the frame into each pipeline instead of moving the standardization). This stack reproduces it to 1e-7 relative on the five datasets used to cross-check, so the validation transfers.

Caveat from that report, carried over: dropping the power transform entirely costs only +0.069% rmse on those 13 datasets, so that view caps what any change to how the transform composes can be worth, and this effect sits below its noise floor — for scale, incidental numerical drift between v8.3.0 and base moved one dataset by 0.60%. The direction is right and the mechanism is a bug fix; the magnitude is not certifiable on TabArena regression. Suggested follow-up on the ticket: validate on skewed positive-target data.

A variant that additionally scale-normalises the yeo-johnson transforms was measured in the same run and is not part of this stack — it gave back about half the gain (+0.017% rmse). Parked on benjamin/res-2639-safepower-scale-normalized.

Tests

The test that #1198 pinned to the old ordering is flipped here, which is the reviewable core of the diff. Added: log1p of the target is finite where log1p of a z-score is not, the "none" preset resolves to no transform, and end-to-end accuracy on a skewed target for three presets.

🤖 Generated with Claude Code

Swaps the two steps of a member's target pipeline: the preset now reshapes the
target in its original units, and the result is standardized afterwards.

Applied to a z-normalised target, `1_plus_log` was `log1p` of a z-score, which
is undefined below -1: for a symmetric target roughly 15% of the rows came out
non-finite and reached the model, since the log presets carry no scaler of
their own. `safepower` was fitted on standardized values, where yeo-johnson
cannot reach the log limit that actually removes skew from a heavy right tail.

Also resolves the `"none"` preset to no transform at all -- it is the identity,
so composing it only costs a pass over the target -- and fixes the docstring of
`_transform_labels_one`, which called its input "unprocessed".

This changes the predictions of the v2, v2.5 and v3 defaults, whose ensembles
use `safepower` for half of their estimators. The v2.6 default (`"none"`) and
every estimator without a target transform are unaffected.

Validated on TabArena regression: 13 datasets, 222 splits per arm, 8
estimators, 1332 fits, -0.031% rmse / -0.069% mae / -0.062% 1-r2, better on
9 of 13 datasets, with the gains concentrated on heavy-tailed positive targets
(healthcare_insurance_expenses -0.23%, diamonds -0.16%,
physiochemical_protein -0.13%). That run measured the same semantics through
an earlier implementation of this change; the two agree to 1e-7 relative on
the five datasets used to cross-check them. The caveat from that report
carries over: dropping the power transform entirely costs only +0.069% rmse on
those 13 datasets, so the view caps what this can be worth and the effect sits
below its noise floor. Follow-up suggested on the ticket is to validate on
skewed positive-target data.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e7d29d7. Configure here.

# The preset reshapes the target in its own units, and only then is
# the result standardized. Reshaping a standardized target instead
# means something else entirely: `1_plus_log` was `log1p` of a
# z-score, undefined wherever that dropped below -1.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment narrates prior transform order

Low Severity

The comment on the new pipeline order explains what the previous ordering did differently (1_plus_log as log1p of a z-score). Team convention is that comments describe only current behavior, not prior behaviour or ticket history.

Fix in Cursor Fix in Web

Triggered by learned rule: Docstrings describe current behavior only — no call sites or code history

Reviewed by Cursor Bugbot for commit e7d29d7. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant